<?php
/**
 * ShopService.php
 *
 * @copyright  2023 beikeshop.com - All Rights Reserved
 * @link       https://beikeshop.com
 * @author     TL <mengwb@guangda.work>
 * @created    2023-05-10 17:09:21
 * @modified   2023-05-10 17:09:21
 */

namespace Plugin\MultiSeller\Services;

use Beike\Models\Order;
use Beike\Repositories\OrderTotalRepo;
use Beike\Seller\Repositories\OrderRepo;
use Beike\Seller\Repositories\ProductRepo;
use Beike\Seller\Repositories\SellerCategoryRepo;
use Beike\Seller\Repositories\SellerRepo;
use Beike\Seller\Repositories\SellerTransactionRepo;
use Beike\Services\StateMachineService;
use Plugin\MultiSeller\Http\Resources\SellerResource;

class ShopService
{
    private static $productsCache = null;

    /**
     * @param int   $productId
     * @param array $productIds
     * @return array
     */
    public static function getSellerByProductId(int $productId, array $productIds = [])
    {
        if (! $productIds) {
            $sellerId = ProductRepo::find($productId)->seller_id ?? 0;
            $seller   = SellerRepo::find($sellerId);
        } else {
            if (self::$productsCache === null) {
                $products              = ProductRepo::getBuilder(['product_ids' => $productIds], 0)->select('products.seller_id', 'products.id as product_id')->get()->toArray();
                $ProductIdToSellerIdTo = array_column($products, 'seller_id', 'product_id');
                $sellers               = SellerRepo::getSellersByIds(array_column($products, 'seller_id'));
                self::$productsCache   = [];
                foreach ($productIds as $id) {
                    $sellerId                 = $ProductIdToSellerIdTo[$id]               ?? 0;
                    self::$productsCache[$id] = $sellers->where('id', $sellerId)->first() ?? [];
                }
            }
            $seller = self::$productsCache[$productId] ?? [];
        }
        if (! $seller) {
            return [
                'id'                  => 0,
                'store_name'          => trans('MultiSeller::common.self'),
                'email'               => system_setting('base.email', ''),
                'status'              => 1,
                'settings'            => [
                    'customer_service_qrcode' => plugin_setting('multi_seller.customer_service_qrcode', ''),
                    'customer_service_link'   => plugin_setting('multi_seller.customer_service_link', ''),
                    'customer_service_icon'   => plugin_setting('multi_seller.customer_service_icon', ''),
                ],
                'created_at'          => '',
                'logo'                => image_resize(system_setting('base.logo', '')),
                'seller_group_name'   => trans('MultiSeller::common.self'),
            ];
        }

        return (new SellerResource($seller))->jsonSerialize();
    }

    /**
     * @param $cartList
     * @return array
     */
    public static function cartListGroupBySeller($cartList)
    {
        $productIds = array_column($cartList, 'id');

        $newCartList = [];
        foreach ($cartList as $item) {
            $seller = self::getSellerByProductId($item['product_id'], $productIds) ?: ['store_name' => trans('MultiSeller::common.self'), 'id' => 0];
            if (! isset($newCartList[$seller['id']])) {
                $newCartList[$seller['id']] = [
                    'seller_id'  => $seller['id'],
                    'store_name' => $seller['store_name'],
                    'list'       => [],
                ];
            }
            $newCartList[$seller['id']]['list'][] = $item;
        }

        return array_values($newCartList);
    }

    /**
     * @param $parentOrder
     * @param $data
     * @return void
     */
    public static function createSubOrder($parentOrder, $data)
    {
        $carts                             = $data['carts']    ?? [];
        $carts                             =  self::cartListGroupBySeller($carts['carts']);
        $carts                             = array_column($carts, null, 'seller_id');
        $parentOrder->shipping_method_code = 'seller';
        $parentOrder->shipping_method_name = trans('MultiSeller::common.seller_decision_shipping');
        // 只有一个商户，不需要拆单，只需要设置订单的商户id和商品的佣金率
        if (count($carts) == 1) {
            $cart                   = array_shift($carts);
            $parentOrder->seller_id = $cart['seller_id'];
            $sellerGroup            = SellerRepo::find($parentOrder->seller_id)->group ?? null;
            if($sellerGroup) {
                $parentOrder->orderProducts->map(function ($item) use ($sellerGroup, $cart) {
                    $item->seller_id                = $cart['seller_id'];
                    $item->store_commission_flat    = $sellerGroup->fee_sale_flat;
                    $item->store_commission_percent = $sellerGroup->fee_sale_percent;
                    $item->seller_amount            = $item->price * $item->quantity - ($sellerGroup->fee_sale_flat + $item->price * $item->quantity * $sellerGroup->fee_sale_percent / 100);
                    $item->save();

                    return $item;
                });
            }
        }
        $parentOrder->save();

        $tTotals    = $data['totals']   ?? [];
        $totals     = [];
        foreach ($tTotals as $item) {
            if ($item['code'] == 'order_total') { // 订单总计只用于当前订单，不用于子订单，子订单的订单总计从其他 order total 中计算
                continue;
            }
            if (! isset($totals[$item['seller_id']])) {
                $totals[$item['seller_id']] = [];
            }
            $totals[$item['seller_id']][] = $item;
        }
        foreach ($totals as $sellerId => &$sellerTotals) {
            $amount         = array_sum(array_column($sellerTotals, 'amount'));
            $sellerTotals[] = [
                'code'          => 'order_total',
                'title'         => trans('shop/carts.order_total'),
                'amount'        => $amount,
                'amount_format' => currency_format($amount),
            ];
        }

        foreach ($carts as $sellerCarts) {
            $order                       = $parentOrder->replicate();
            $order->seller_id            = $sellerCarts['seller_id'];
            $order->parent_id            = $parentOrder->id;
            $order->number               = OrderRepo::generateOrderNumber();
            $order->shipping_method_code = 'seller';
            $order->shipping_method_name = trans('MultiSeller::common.seller_decision_shipping');

            $orderTotal   = collect($totals[$sellerCarts['seller_id']])->where('code', 'order_total')->first();
            $order->total = $orderTotal['amount'];

            $order->saveOrFail();

            $orderProductData = $sellerCarts['list'];
            $sellerGroup      = SellerRepo::find($order->seller_id)->group ?? null;
            if($sellerGroup) {
                $orderProductData = array_map(function ($item) use ($sellerGroup, $order) {
                    return array_merge($item, [
                        'seller_id'                => $order->seller_id,
                        'store_commission_flat'    => $sellerGroup->fee_sale_flat,
                        'store_commission_percent' => $sellerGroup->fee_sale_percent,
                        'seller_amount'            => $item['price'] * $item['quantity'] - ($sellerGroup->fee_sale_flat + $item['price'] * $item['quantity'] * $sellerGroup->fee_sale_percent / 100),
                    ]);
                }, $orderProductData);
            }
            \Beike\Seller\Repositories\OrderProductRepo::createOrderProducts($order, $orderProductData);
            OrderTotalRepo::createTotals($order, $totals[$sellerCarts['seller_id']]);
        }
    }

    /**
     * @param Order  $order
     * @param string $status
     * @param string $comment
     * @param bool   $notify
     * @return void
     * @throws \Exception
     */
    public static function changeSubOrderStatus(Order $order, string $status, string $comment, bool $notify)
    {
        if ($status != StateMachineService::PAID) {
            return;
        }
        $subOrders = OrderRepo::getSubOrderByOrderId($order->id);
        if ($subOrders->count() < 1) {
            return;
        }
        foreach ($subOrders as $subOrder) {
            StateMachineService::getInstance($subOrder)->changeStatus(StateMachineService::UNPAID);
            StateMachineService::getInstance($subOrder)->changeStatus($status, $comment, $notify);
        }

        if ($status == 'paid') {
            StateMachineService::getInstance($order)->changeStatus('split', $comment, $notify);
        }
    }

    /**
     * @param Order $order
     * @param array $machines
     * @return array
     */
    public static function getStateMachines(Order $order, array $machines)
    {
        if (is_seller()) {
            return [StateMachineService::PAID => $machines[StateMachineService::PAID]];
        }

        $hasSubOrder = Order::query()->where('parent_id', $order->id)->count();
        if ($order->parent_id  > 0 || ! $hasSubOrder) {
            // 如果是子订单或没有子订单的主订单, 支付的时候执行更新销量喝扣减库存（因为主订单和子订单都会变成已付款）
            $machines[StateMachineService::UNPAID][StateMachineService::PAID] = ['updateStatus', 'addHistory', 'updateSales', 'subStock'];

            $addTransactionToSeller = function () use ($order) {
                foreach ($order->orderProducts as $orderProduct) {
                    SellerTransactionRepo::create([
                        'seller_id'        => $order->seller_id,
                        'order_product_id' => $orderProduct->id,
                        'order_id'         => $order->id,
                        'product_id'       => $orderProduct->product_id,
                        'amount'           => $orderProduct->seller_amount,
                        'description'      => 'Sales revenue. Order ID: ' . $order->id,
                    ]);
                }
                foreach ($order->orderTotals as $orderTotal) {
                    if (in_array($orderTotal['code'], ['sub_total', 'order_total'])) {
                        continue;
                    }
                    SellerTransactionRepo::create([
                        'seller_id'   => $order->seller_id,
                        'order_id'    => $order->id,
                        'amount'      => $orderTotal->value,
                        'description' => "$orderTotal->title($orderTotal->code). Order ID: $order->id",
                    ]);
                }
            };
            $machines[StateMachineService::PAID][StateMachineService::COMPLETED][]    = $addTransactionToSeller;
            $machines[StateMachineService::SHIPPED][StateMachineService::COMPLETED][] = $addTransactionToSeller;
        } elseif ($order->parent_id == 0 && OrderRepo::hasSubOrder($order->id)) { // 如果是主订单, 支付的时候执行notifyUpdateOrder（因为主订单和子订单都会变成已付款）
            $machines[StateMachineService::UNPAID][StateMachineService::PAID] = ['updateStatus', 'addHistory', 'notifyUpdateOrder'];
            $machines[StateMachineService::PAID]['split']                     = ['updateStatus', 'addHistory', 'notifyUpdateOrder'];
        }

        return $machines;
    }

    /**
     * @return array
     */
    public static function getMenus()
    {
        $menus = [
            'route'    => 'sellers.index',
            'title'    => trans('MultiSeller::common.sellers'),
            'icon'     => 'bi bi-shop',
            'prefixes' => ['sellers', 'seller_groups', 'transactions', 'seller_settings', 'withdraws', 'shipping'],
            'children' => [
                ['route' => 'sellers.index', 'title' => trans('MultiSeller::common.sellers'), 'prefixes' => ['sellers']],
                ['route' => 'seller_groups.index', 'title' => trans('MultiSeller::common.seller_groups'), 'prefixes' => ['seller_groups']],
                ['route' => 'transactions.index', 'title' => trans('MultiSeller::common.transactions'), 'prefixes' => ['transactions']],
                ['route' => 'withdraws.index', 'title' => trans('MultiSeller::common.withdraws'), 'prefixes' => ['withdraws']],
                ['route' => 'shipping.index', 'title' => trans('MultiSeller::common.shipping'), 'prefixes' => ['shipping']],
                ['route' => 'seller_settings.index', 'title' => trans('MultiSeller::common.seller_configs'), 'prefixes' => ['seller_settings']],
            ],
        ];

        return $menus;
    }

    /**
     * @return array[]
     */
    public static function getPermissionsTable()
    {
        $permissions = [
            [
                'title'       => trans('MultiSeller::common.sellers'),
                'permissions' => [
                    [
                        'code' => 'sellers_index',
                        'name' => trans('MultiSeller::common.seller_index'),
                    ],
                    [
                        'code' => 'sellers_show',
                        'name' => trans('MultiSeller::common.seller_show'),
                    ],
                    [
                        'code' => 'sellers_create',
                        'name' => trans('MultiSeller::common.seller_create'),
                    ],
                    [
                        'code' => 'sellers_update',
                        'name' => trans('MultiSeller::common.seller_update'),
                    ],
                ],
            ],
            [
                'title'       => trans('MultiSeller::common.seller_groups'),
                'permissions' => [
                    [
                        'code' => 'seller_groups_index',
                        'name' => trans('MultiSeller::common.seller_group_index'),
                    ],
                    [
                        'code' => 'seller_groups_show',
                        'name' => trans('MultiSeller::common.seller_group_show'),
                    ],
                    [
                        'code' => 'seller_groups_create',
                        'name' => trans('MultiSeller::common.seller_group_create'),
                    ],
                    [
                        'code' => 'seller_groups_update',
                        'name' => trans('MultiSeller::common.seller_group_update'),
                    ],
                    [
                        'code' => 'seller_groups_delete',
                        'name' => trans('MultiSeller::common.seller_group_delete'),
                    ],
                ],
            ],
            [
                'title'       => trans('MultiSeller::common.transactions'),
                'permissions' => [
                    [
                        'code' => 'transactions_index',
                        'name' => trans('MultiSeller::common.transaction_index'),
                    ],
                ],
            ],
            [
                'title'       => trans('MultiSeller::common.withdraws'),
                'permissions' => [
                    [
                        'code' => 'withdraws_index',
                        'name' => trans('MultiSeller::common.withdraw_index'),
                    ],
                    [
                        'code' => 'withdraws_update',
                        'name' => trans('MultiSeller::common.withdraw_update'),
                    ],
                ],
            ],
            [
                'title'       => trans('MultiSeller::common.shipping'),
                'permissions' => [
                    [
                        'code' => 'shipping_index',
                        'name' => trans('MultiSeller::common.shipping_index'),
                    ],
                    [
                        'code' => 'shipping_show',
                        'name' => trans('MultiSeller::common.shipping_show'),
                    ],
                    [
                        'code' => 'shipping_create',
                        'name' => trans('MultiSeller::common.shipping_create'),
                    ],
                    [
                        'code' => 'shipping_update',
                        'name' => trans('MultiSeller::common.shipping_update'),
                    ],
                    [
                        'code' => 'shipping_delete',
                        'name' => trans('MultiSeller::common.shipping_update'),
                    ],
                ],
            ],
        ];

        return $permissions;
    }

    /**
     * 商户店铺首页菜单
     * @param $sellerId
     * @return array
     */
    public static function getSellerMenus($sellerId)
    {
        $categories = SellerCategoryRepo::list($sellerId, ['active' => 1]);
        $data       = [];
        foreach ($categories as $category) {
            $data[] = [
                'name' => $category->description->name,
                'link' => shop_route('seller_categories.show', ['sid' => $sellerId, 'id' => $category->id]),
            ];
        }

        return $data;
    }
}
